package com.hlkj.warboot.configurer.security;

import com.hlkj.warboot.configurer.security.authentication.handler.MyAuthenticationFailHandler;
import com.hlkj.warboot.configurer.security.authentication.handler.MyAuthenticationSuccessHandler;
import com.hlkj.warboot.configurer.security.authentication.provider.MyAuthenticationProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.WebAuthenticationDetails;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * @Description Spring Security 自定义核心配置
 * @Author 李星
 * @Date 2019/6/29 22:53
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true) // 开启方法注解支持
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private MyAuthenticationProvider myAuthenticationProvider; // 自定义认证组件

    @Resource
    private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> authenticationDetailsSource; // 自定义附加参数认证

    @Resource
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler; // 认证成功回调

    @Resource
    private MyAuthenticationFailHandler myAuthenticationFailHandler; // 认证失败回调

    /*
     * @Description 自定义认证管理器
     * @Author 李星
     * @Date 2019/6/1 1:04
     * @Param [auth]
     * @return void
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(myAuthenticationProvider); // 将自定义认证组件加入认证管理器
    }

    /*
     * @Description 全局资源请求拦截策略（哪些请求需要身份认证、相关权限后才可访问）
     * @Author 李星
     * @Date 2019/5/30 21:28
     * @Param [http]
     * @return void
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                /*
                 * @Description TODO ====================================================允许用户使用基于表单的登录进行身份验证
                 *
                 */
                .formLogin()
                .loginPage("/sys/admin/toLogin") // TODO 跳转到登录页面的地址
                .loginProcessingUrl("/sys/admin/login") // TODO 登陆认证的地址
                .usernameParameter("account")  // TODO 登陆账号字段
                .passwordParameter("pass")     // TODO 登陆密码字段
                .authenticationDetailsSource(authenticationDetailsSource) // TODO 认证时新增附加字段
                .successHandler(myAuthenticationSuccessHandler) // TODO 认证成功回调
                .failureHandler(myAuthenticationFailHandler) // TODO 认证失败回调
                /*
                 * @Description TODO ============================================================================退出登陆
                 *
                 */
                .and().logout()
                .logoutUrl("/sys/admin/logout") // TODO 退出登陆的地址
                //.addLogoutHandler( (request, response, authentication) -> LoggerUtil.info( "注销" ) )
                //.logoutSuccessHandler( (request, response, authentication) -> LoggerUtil.info( "注销成功" ) )
                .invalidateHttpSession(true) // TODO 退出登陆成功后使HttpSession失效
                .logoutSuccessUrl("/sys/admin/toLogin") // TODO 退出登陆成功后重定向到的地址
                // 其他
                .and().headers().frameOptions().disable()
                .and().csrf().disable() // 开启会报401,需要在html中做处理
                .httpBasic()
                /*
                 * @Description TODO ===============================================================拦截所有请求进行身份验证
                 *
                 */
                .and().authorizeRequests()
                .antMatchers(
                        "/"
                        , "/static/**" // 静态页面
                        , "/asyn/sendMail" // 发送邮件
                        , "/sys/admin/verifyCode" // 图型验证码
                        , "/sys/admin/toLogin" // 跳转到登陆页面
                        , "/sys/admin/toRegister" // 跳转到注册页面
                        , "/sys/admin/register" // 注册操作
                        , "/sys/admin/toForgetPass" // 跳转到修改密码页面
                        , "/sys/admin/modifyPass" // 修改密码
                        , "/laboratory/**"                // TODO ==== 测试模块
                        , "https://open.weixin.qq.com/**" // TODO ==== 微信第三方接口
                        , "/wx/**"                        // TODO ==== 微信H5活动
                        , "/demo/**"                        // TODO ==== 微信H5活动
                        , "/OrderPushForXb/**"            // TODO ==== 测试
                        , "/xxlJob/**"                    // TODO ==== xxl_job测试接口
                        , "/asyn/**"                      // TODO ==== 异步接口
                ).permitAll() // TODO 请求白名单
                //.antMatchers( "/sys/admin/page/**").access("hasAnyRole('ROLE_SUPERADMIN') or hasAnyAuthority( '/sys/admin/page/' )") // 不建议采用此方式授权
                //.anyRequest().authenticated() // 对白名单以外的请求进行身份认证
                .anyRequest().access("@myAuthentization.isAuthentizated(request, authentication)") // TODO 更具当前请求的url动态授权
                .and().exceptionHandling().accessDeniedPage("/403") // TODO 授权失败跳转到403
        ;
    }
}
